package com.alibaba.service;

import com.alibaba.common.ResponseResult;
import com.alibaba.define.domain.CommentDO;
import com.alibaba.define.domain.UserDO;
import com.alibaba.define.domain.vo.CommentVO;
import com.alibaba.define.domain.vo.PageVO;
import com.alibaba.define.service.CommentService;
import com.alibaba.define.service.request.AddCommentRequest;
import com.alibaba.enums.CommentTypeEnum;
import com.alibaba.fastjson.JSON;
import com.alibaba.manager.CommentManager;
import com.alibaba.manager.UserManager;
import com.alibaba.utils.BeanCopyUtils;
import com.alibaba.utils.SecurityUtils;
import com.github.houbb.sensitive.word.core.SensitiveWordHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.alibaba.define.enums.AppHttpCodeEnum.*;

/**
 * @author : hanyang
 * @date : 2023-11-04 16:10
 **/

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Resource
    CommentManager commentManager;

    @Resource
    UserManager userManager;

    @Override
    public ResponseResult<PageVO> commentList(Integer commentType, Long articleId, Integer pageNum, Integer pageSize) {
        PageVO pageVO = new PageVO();
        List<CommentVO> commentVOS = new ArrayList<>();
        try {
            long start = System.currentTimeMillis();
            List<CommentDO> rootCommentDOS = commentManager.selectRootCommentByArticleId(commentType, articleId, pageNum, pageSize);
            log.info("CommentServiceImpl#commentList() selectRootCommentByArticleId request[commentType:{}, articleId:{}, pageNum:{}, pageSize:{}] result:{}", commentType, articleId, pageNum, pageSize, JSON.toJSONString(rootCommentDOS));
            if (CollectionUtils.isEmpty(rootCommentDOS)) {
                pageVO.setRows(commentVOS);
                return ResponseResult.ok(pageVO);
            }
            // 获取所有根评论的用户ID,并查询昵称，建立ID到昵称的映射
            Set<Long> userIds = rootCommentDOS.stream().map(CommentDO::getCreateBy).collect(Collectors.toSet());
            Map<Long, UserDO> userIdNicknameMap = userManager.batchQueryUserDOS(userIds);
            // 批量查询子评论
            Set<Long> rootIds = rootCommentDOS.stream().map(CommentDO::getId).collect(Collectors.toSet());
            List<CommentDO> childrenComments = commentManager.batchQueryChildrenComments(rootIds, commentType);
            Map<Long, List<CommentDO>> childrenMap = childrenComments.stream().collect(Collectors.groupingBy(CommentDO::getRootId));
            // 获取所有子评论的创建者ID和被回复者的ID，查询昵称，建立ID到昵称的映射
            Set<Long> childrenCommentUserIds = childrenComments.stream()
                    .flatMap(commentDO -> Stream.of(commentDO.getToCommentUserId(), commentDO.getCreateBy()))
                    .collect(Collectors.toSet());
            Map<Long, UserDO> childrenCommentUserDOMap = userManager.batchQueryUserDOS(childrenCommentUserIds);

            // 构建评论VO列表
            commentVOS = rootCommentDOS.stream().map(commentDO -> {
                CommentVO commentVO = BeanCopyUtils.copyBean(commentDO, CommentVO.class);

                // 从映射中获取昵称
                UserDO queryUser = userIdNicknameMap.get(commentDO.getCreateBy());
                commentVO.setUsername(queryUser.getNickName());
                commentVO.setAvatar(queryUser.getAvatar());
                List<CommentDO> commentDOS = childrenMap.get(commentDO.getId());

                // 子评论的转换逻辑
                if(!CollectionUtils.isEmpty(commentDOS)) {
                    List<CommentVO> childrenCommentVOS = convertToCommentVOList(commentDOS, childrenCommentUserDOMap);
                    commentVO.setChildren(childrenCommentVOS);
                }
                return commentVO;
            }).collect(Collectors.toList());
            pageVO.setRows(commentVOS);
            pageVO.setTotal(commentManager.queryCommentCountByCondition(articleId, commentType));
            long end = System.currentTimeMillis();
            log.info("coast time:{}", end - start);
            return ResponseResult.ok(pageVO);
        } catch (Exception e) {
            log.error("CommentServiceImpl#commentList Exception:{}", JSON.toJSONString(e));
        }
        return ResponseResult.error(SYSTEM_EXECUTE_ERROR.getCode(), SYSTEM_EXECUTE_ERROR.getMsg());
    }

    @Override
    public ResponseResult<Void> addComment(AddCommentRequest addCommentRequest) {
        try {
            // 参数校验
            if (!this.checkAddCommentRequest(addCommentRequest)) {
                log.info("CommentServiceImpl#addComment() request check error! request:{}", JSON.toJSONString(addCommentRequest));
                return ResponseResult.error(WRONG_PARAMETER.getCode(), WRONG_PARAMETER.getMsg());
            }
            // 敏感词检测
            if (SensitiveWordHelper.contains(addCommentRequest.getContent())) {
                log.warn("comment has sensitive word comment:{}", addCommentRequest.getContent());
                return ResponseResult.error(HAS_SENSITIVE_WORD.getCode(), HAS_SENSITIVE_WORD.getMsg());
            }
            // 构建CommentDO
            CommentDO commentDO = this.buildCommentDOByRequest(addCommentRequest);
            Integer added = commentManager.addComment(commentDO);
            if (!Objects.equals(added, 1)) {
                log.error("CommentServiceImpl#addComment() database add error parameter:{}", JSON.toJSONString(commentDO));
                return ResponseResult.error(ADD_FAIL.getCode(), ADD_FAIL.getMsg());
            }
            return ResponseResult.ok();
        } catch (Exception e) {
            log.error("CommentServiceImpl#addComment() Exception:{}", JSON.toJSONString(e));
        }
        return ResponseResult.error(SYSTEM_EXECUTE_ERROR.getCode(), SYSTEM_EXECUTE_ERROR.getMsg());
    }

    private List<CommentVO> convertToCommentVOList(List<CommentDO> commentDOS, Map<Long, UserDO> userNicknameMap) {
        return commentDOS.stream().map(commentDO -> {
            CommentVO commentVO = BeanCopyUtils.copyBean(commentDO, CommentVO.class);

            commentVO.setToCommentUserName(userNicknameMap.get(commentDO.getToCommentUserId()).getNickName());
            UserDO createUser = userNicknameMap.get(commentDO.getCreateBy());
            commentVO.setUsername(createUser.getNickName());
            commentVO.setAvatar(createUser.getAvatar());
            return commentVO;
        }).collect(Collectors.toList());
    }

    private boolean checkAddCommentRequest(AddCommentRequest request) {
        if (Objects.isNull(request)) {
            return false;
        }
        return request.getType() != null && request.getArticleId() != null && request.getRootId() != null && !StringUtils.isEmpty(request.getContent()) && request.getToCommentUserId() != null && request.getToCommentId() != null;
    }


    private CommentDO buildCommentDOByRequest(AddCommentRequest request) {
        Long userId = SecurityUtils.getUserId();
        CommentDO commentDO = BeanCopyUtils.copyBean(request, CommentDO.class);
        commentDO.setCreateBy(userId).setUpdateBy(userId);
        return commentDO;
    }
}
